import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

import compoundDB.core.Compound;
import compoundDB.core.Molecule;
import compoundDB.io.FileMode;
import compoundDB.io.MoleculeReader;


public class MDLReader implements MoleculeReader {

	private BufferedReader reader = null;
	private boolean hasRead = false;
	
	@Override
	public void close() {
		if(reader != null) {
			try {
				reader.close();
			} catch (IOException e) {
				System.err.print("MDLReader: Something happened while closing the file");
			}
			reader = null;
		}
		
		hasRead = false;
	}

	@Override
	public int compoundsRemaining() throws IOException {
		if(hasRead) {
			return 0;
		}
		
		return 1;
	}

	@Override
	public boolean hasNext() throws IOException {
		return !hasRead;
	}

	@Override
	public boolean isOpen() {
		return (reader != null);
	}

	@Override
	public List<String> listCompounds(int limit) throws IOException {
		if(reader == null) {
			throw new IOException("No open file");
		}
		// TODO
		return null;
	}

	@Override
	public boolean multiMolecule() {
		return false;
	}

	@Override
	public int numberOfCompounds() throws IOException {
		if(reader == null) {
			throw new IOException("No open file");
		}
		
		return 1;
	}

	@Override
	public void open(String filename) throws FileNotFoundException {
		File f = new File(filename);
		if(!f.exists()) {
			throw new FileNotFoundException(filename);
		}
		if(!f.canRead()) {
			//something else bad happened
		}
		
		reader = new BufferedReader(new FileReader(f));
	}

	@Override
	public void open(String filename, FileMode flags)
			throws FileNotFoundException, IllegalArgumentException {
		if(flags != FileMode.READ && flags != FileMode.READWRITE){
			throw new IllegalArgumentException("flags");
		}
		
		open(filename);
	}

	@Override
	public int position() throws IOException {
		if(reader == null) {
			throw new IOException("No open file");
		}
		
		if(hasRead) {
			return 1;
		}
		return 0;
	}

	@Override
	public Compound readCompound() throws IOException {
		if(reader == null) {
			throw new IOException("No open file");
		} else if(hasRead) {
			throw new IOException("No more compounds");
		}
		hasRead = true;
		
		/* Find the counts line*/
		String name = "";
		String line = reader.readLine();
		
		while(true) {
			if(Common.CTabParser.isCountsLine(line))
				break;
			name = line;
			line = reader.readLine();
		}
		
		Common.CTabParser parser = new Common.CTabParser(line);
		
		/* Find the first line of the atom table...*/
		int atomOffset = 0;
		while(true) {
			line = reader.readLine();
			if(Common.CTabParser.isAtomLine(line))
				break;
			if(line.equals("@<TRIPOS>ATOM")) {
				atomOffset = 16;
				break;
			}
		}
		for(int i = 0; i < parser.getAtomCount(); i++) {
			parser.addAtom(reader.readLine().substring(atomOffset));
		}
		
		/* Find the first line of the bond table...*/
		boolean spaceDelimited = false;
		while(true) {
			line = reader.readLine();
			if(Common.CTabParser.isBondLine(line)) {
				break;
			}
			if(line.equals("@<TRIPOS>BOND")) {
				spaceDelimited = true;
				break;
			}
		}
		for(int i = 0; i < parser.getBondCount(); i++) {
			if(spaceDelimited) {
				String[] s = reader.readLine().trim().split("\\s+");
				s[3] = s[3].equals("ar") ? "4" : s[3];
				parser.addBond(String.format("%3s%3s%3s", s[1], s[2], s[3]));
			} else {
				parser.addBond(reader.readLine());
			}
		}
		
		Compound c = new Compound((int)UUID.randomUUID().getLeastSignificantBits(), 0);
		
		c.addName(name);
		c.setProperty("structure", Molecule.serialize(parser.buildMolecule()));
		
		return c;
	}

	@Override
	public void seek(int position) throws IOException {
		if(reader == null) {
			throw new IOException("No open file");
		} else if(position > 1) {
			throw new IOException("Invalid position for file");
		}

		if(position == 1) {
			hasRead = true;
		} else {
			hasRead = false;
		}
	}

	@Override
	public List<String> supportedTypes() {
		List<String> l = new LinkedList<String>();
		l.add(".mdl");
		return l;
	}

}
